package com.hsurosy.domain.strategy.service.rule.chain.impl;

import com.hsurosy.domain.strategy.repository.IStrategyRepository;
import com.hsurosy.domain.strategy.service.armory.IStrategyDispatch;
import com.hsurosy.domain.strategy.service.rule.chain.AbstractLogicChain;
import com.hsurosy.domain.strategy.service.rule.chain.factory.DefaultChainFactory;
import com.hsurosy.types.common.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;

/**
 * @Author Hsu琛君珩
 * @Date 2024-10-19 1:16
 * @Description 权重方法
 * @Version: v1.0.0
 */
@Slf4j
@Component("rule_weight")
public class RuleWeightLogicChain extends AbstractLogicChain {

    @Resource
    private IStrategyRepository repository;
    @Resource
    private IStrategyDispatch strategyDispatch;

    // 模拟用户的积分值，实际使用时可能需要从数据库获取
    public Long userScore = 0L;

    /**
     * 权重规则过滤：根据用户的积分和权重规则确定用户符合的奖品组，并接管抽奖流程
     * 规则格式：4000:102,103,104,105 5000:102,103,104,105,106,107 6000:102,103,104,105,106,107,108,109
     * 根据用户的积分找到最匹配的权重区间，如果找到符合条件的奖品组，则进行抽奖
     *
     * @param userId 用户ID，用于标识抽奖用户
     * @param strategyId 抽奖策略ID，用于标识当前的抽奖策略
     * @return 返回奖品ID，或者放行到下一个责任链节点
     */
    @Override
    public DefaultChainFactory.StrategyAwardVO logic(String userId, Long strategyId) {
        log.info("抽奖责任链-权重开始 userId: {} strategyId: {} ruleModel: {}", userId, strategyId, ruleModel());

        // 1. 查询当前策略的权重规则值
        String ruleValue = repository.queryStrategyRuleValue(strategyId, ruleModel());

        // 2. 解析权重规则，生成权重和奖品的映射表
        Map<Long, String> analyticalValueGroup = getAnalyticalValue(ruleValue);
        if (null == analyticalValueGroup || analyticalValueGroup.isEmpty()) {
            log.warn("抽奖责任链-权重警告【策略配置权重，但ruleValue未配置相应值】 userId: {} strategyId: {} ruleModel: {}", userId, strategyId, ruleModel());
            return next().logic(userId, strategyId);
        }

        // 3. 对权重值进行排序，方便匹配用户的积分
        List<Long> analyticalSortedKeys = new ArrayList<>(analyticalValueGroup.keySet());
        Collections.sort(analyticalSortedKeys);

        // 4. 根据用户积分找到最接近的权重值区间
        // 找到用户的积分能够匹配到的最大权重值区间
        Long nextValue = analyticalSortedKeys.stream()
                .sorted(Comparator.reverseOrder())  // 逆序排序，优先匹配更大的权重值
                .filter(analyticalSortedKeyValue -> userScore >= analyticalSortedKeyValue)  // 筛选出用户积分大于等于权重值的区间
                .findFirst()  // 找到第一个匹配的区间
                .orElse(null);  // 如果找不到符合条件的权重值，则返回null

        // 5. 如果找到符合条件的权重值区间，进行抽奖并返回奖品ID
        if (null != nextValue) {
            Integer awardId = strategyDispatch.getRandomAwardId(strategyId, analyticalValueGroup.get(nextValue));
            log.info("抽奖责任链-权重接管 userId: {} strategyId: {} ruleModel: {} awardId: {}", userId, strategyId, ruleModel(), awardId);
            return DefaultChainFactory.StrategyAwardVO.builder()
                    .awardId(awardId)
                    .logicModel(ruleModel())
                    .build();
        }

        // 6. 如果用户的积分不匹配任何权重区间，继续执行下一个责任链节点
        log.info("抽奖责任链-权重放行 userId: {} strategyId: {} ruleModel: {}", userId, strategyId, ruleModel());
        return next().logic(userId, strategyId);  // 放行到下一个责任链节点
    }

    @Override
    protected String ruleModel() {
        return DefaultChainFactory.LogicModel.RULE_WEIGHT.getCode(); // 当前是权重规则的处理节点
    }

    /**
     * 解析权重规则值
     *
     * @param ruleValue 规则字符串，格式为 "4000:102,103,104,105 5000:102,103,104,105,106,107"
     * @return 返回解析后的权重规则映射表
     */
    private Map<Long, String> getAnalyticalValue(String ruleValue) {
        // 将规则按空格分割为多个权重组
        String[] ruleValueGroups = ruleValue.split(Constants.SPACE);
        Map<Long, String> ruleValueMap = new HashMap<>();
        for (String ruleValueKey : ruleValueGroups) {
            // 每个 ruleValueKey 是格式如 "4000:102,103,104,105"
            // 检查输入是否为空
            if (ruleValueKey == null || ruleValueKey.isEmpty()) {
                return ruleValueMap;
            }
            // 分割字符串以获取键（权重）和值（奖品组）
            String[] parts = ruleValueKey.split(Constants.COLON);  // 按冒号分
            if (parts.length != 2) {
                throw new IllegalArgumentException("rule_weight rule_rule invalid input format" + ruleValueKey);
            }
            // parts[0] 是权重值，parts[1] 是奖品ID列表
            ruleValueMap.put(Long.parseLong(parts[0]), ruleValueKey);  // 以权重值为键，完整的规则为值
        }
        return ruleValueMap;
    }
}
